package main

import (
	"context"
	"fmt"
	"time"

	"go.etcd.io/etcd/client/v3"
)

// 实现分布式锁
func main() {

	cfg := clientv3.Config{
		Endpoints: []string{"192.168.0.121:2379"},

		DialTimeout: 5 * time.Second,
	}

	client, err := clientv3.New(cfg)
	if err != nil {
		fmt.Println(err)
		return
	}

	//1.创建租约，并自动续租
	lease := clientv3.NewLease(client)
	// 5s租约
	grant, err := lease.Grant(context.TODO(), 5)
	if err != nil {
		fmt.Println(err)
		return
	}
	leaseId := grant.ID
	ctx, cancel := context.WithCancel(context.TODO())
	//2. 释放锁，主动取消续租,删除租约(关联的kv也被删除)
	defer func() {
		cancel()
		lease.Revoke(context.TODO(), leaseId)
	}()
	aliveChan, err := lease.KeepAlive(ctx, leaseId)
	if err != nil {
		fmt.Println(err)
		return
	}
	go func() {
		for {
			select {
			case keepResp := <-aliveChan:
				if keepResp == nil {
					fmt.Println("租约已经失效")
					return
				} else {
					fmt.Println("收到自动续租应答", keepResp.ID)
				}
			}
		}
	}()

	//3.抢占key，事务处理
	kv := clientv3.NewKV(client)
	txn := kv.Txn(context.TODO())
	txn.If(clientv3.Compare(clientv3.CreateRevision("/cron/lock/job8"), "=", 0)). //锁未被抢占
		//抢锁成功
		Then(clientv3.OpPut("/cron/lock/job8", "", clientv3.WithLease(leaseId))).
		//抢锁失败
		Else(clientv3.OpGet("/cron/lock/job8"))
	txnResp, err := txn.Commit()
	if err != nil {
		fmt.Println(err)
		return
	}
	// 为满足条件，锁已被抢占
	if !txnResp.Succeeded {
		fmt.Println("锁被占用", string(txnResp.Responses[0].GetResponseRange().Kvs[0].Value))
		return
	}

	//4.业务处理
	fmt.Println("处理业务")
	time.Sleep(10 * time.Second)

}
